/*
 * Copyright 2012-2013 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.column;

import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.BrowserEvents;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
import com.google.gwt.safehtml.shared.SafeHtml;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;

import finbudgettable.client.ui.grid.CellGrid;
import finbudgettable.client.ui.grid.filter.Filter;

public class GridHeaderCell extends AbstractCell<String> implements ColumnMenuContainer {

    interface Template extends SafeHtmlTemplates {

        @Template("<div id=\"{0}\" class=\"{1}\">{2}</div>")
        SafeHtml header(String id, String className, SafeHtml content);

        @Template("<div id=\"{0}\" class=\"{1}\">{2}</div>")
        SafeHtml caption(String id, String className, String caption);

        @Template("<div id=\"{0}\" class=\"{1}\"></div>")
        SafeHtml resize(String id, String className);

        @Template("<div id=\"{0}\" class=\"{1}\"></div>")
        SafeHtml button(String id, String className);

    }

    private static Template template;

    private final CellGrid grid;
    private final GridColumn<?> column;
    private final ColumnMenu columnMenu;
    private final String headerElementId;
    private final String captionElementId;
    private final String buttonElementId;
    private final String resizeElementId;

    private boolean inFocus;

    public GridHeaderCell(CellGrid grid, GridColumn<?> column, ColumnMenu columnMenu) {
        super(BrowserEvents.CLICK, BrowserEvents.DBLCLICK, BrowserEvents.MOUSEOUT, BrowserEvents.MOUSEOVER);
        this.grid = grid;
        this.column = column;
        this.columnMenu = columnMenu;
        this.headerElementId = DOM.createUniqueId();
        this.captionElementId = DOM.createUniqueId();
        this.buttonElementId = DOM.createUniqueId();
        this.resizeElementId = DOM.createUniqueId();
        if (template == null) {
            template = GWT.create(Template.class);
        }
        // Check if we are running on Android or iOS
        String platform = Window.Navigator.getPlatform();
        if (platform != null) {
        	platform = platform.toLowerCase();
        	if (platform.indexOf("android") >= 0 || platform.indexOf("ipad") >=0 || platform.indexOf("iphone") >= 0) {
        		inFocus = true;
        	}
        }
    }

    public Element getCaptionElement() {
        return Document.get().getElementById(captionElementId);
    }

    public Element getButtonElement() {
        return Document.get().getElementById(buttonElementId);
    }

    public Element getRightResizeElement() {
        return Document.get().getElementById(resizeElementId);
    }

    @Override
    public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event, ValueUpdater<String> stringValueUpdater) {
        super.onBrowserEvent(context, parent, value, event, stringValueUpdater);
        String eventType = event.getType();
        if (BrowserEvents.CLICK.equals(eventType)) {
            if (event.getEventTarget().equals(getCaptionElement())) {
                grid.sortColumn(column);
            } else {
                Element button = getButtonElement();
                if (button != null) {
                    if (event.getEventTarget().equals(button)) {
                        if (columnMenu != null) {
                            Filter filter = grid.getFilter().getFilter(column.getFieldName());
                            columnMenu.show(button.getAbsoluteLeft() + 18, button.getAbsoluteTop() + 17, column, filter, this);
                        }
                    }
                }
            }
            if (!inFocus) {
        		inFocus = true;
        		if (getButtonElement() != null) {
        			getButtonElement().setClassName(getButtonCssClassName());
        		}
            }
        } else if (BrowserEvents.MOUSEOVER.equals(eventType)) {
        	if (getButtonElement() != null) {
        		inFocus = true;
        		getButtonElement().setClassName(getButtonCssClassName());
        	}
        } else if (BrowserEvents.MOUSEOUT.equals(eventType)) {
        	if (getButtonElement() != null) {
        		inFocus = false;
    			getButtonElement().setClassName(getButtonCssClassName());
        	}
        }
    }

    @Override
    public void render(Context context, String value, SafeHtmlBuilder sb) {
        if (value != null) {
            Style style = GridColumn.RESOURCES.style();

            SafeHtmlBuilder cellBuilder = new SafeHtmlBuilder();

            if (value != null && !value.isEmpty()) {
                SafeHtml caption = template.caption(captionElementId, style.bColumnHeader__caption(), value);
                cellBuilder.append(caption);
            }

            SafeHtml resize = template.resize(resizeElementId, style.bColumnHeader__resizeRightBorder());
            cellBuilder.append(resize);

            if (columnMenu != null) {
                SafeHtml button = template.button(buttonElementId, getButtonCssClassName());
                cellBuilder.append(button);
            }

            SafeHtml content = cellBuilder.toSafeHtml();
            sb.append(template.header(headerElementId, style.bColumnHeader() + " " + column.getCssClassName(), content));
        }
    }

    private String getButtonCssClassName() {
        SortOrder order = column.getSortOrder();
        Style style = GridColumn.RESOURCES.style();
    	String result = style.bColumnHeader__button() + " ";

        if (column.getGrid().getFilter().getFilter(column.getFieldName()) != null) {
            if (order.equals(SortOrder.ASC)) {
                return result + style.bColumnHeader__button_filter_sortAsc();
            } else if (order.equals(SortOrder.DESC)) {
                return result + style.bColumnHeader__button_filter_sortDesc();
            } else {
                return result + style.bColumnHeader__button_filter();
            }
        }
        if (order.equals(SortOrder.ASC)) {
            return result + style.bColumnHeader__button_sortAsc();
        } else if (order.equals(SortOrder.DESC)) {
            return result + style.bColumnHeader__button_sortDesc();
        } else {
            result += style.bColumnHeader__button_normal();
            if (!inFocus) {
            	result += " " + GridColumn.RESOURCES.style().invisible();
            }
            return result;
        }
    }

	@Override
	public void onMenuClosed() {
		inFocus = false;
		if (getButtonElement() != null) {
			// This is intentional delay. In case this command is executed without delay then if our button was clicked this button
			// is hidden by this command. So as not to hide the button in this scenario the command executed with a delay. During the
			// delay the Click event occures and the button sets inFocus flag.
			(new Timer() {
				@Override
				public void run() {
					getButtonElement().setClassName(getButtonCssClassName());
				}
			}).schedule(100);
		}
	}

}
